<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>实验室耗材管理系统</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        body { font-family: 'Inter', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; }
        .btn { @apply inline-block px-4 py-2 font-semibold text-white rounded-lg shadow-md transition-all duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2; }
        .btn:hover { @apply shadow-lg -translate-y-0.5; }
        .btn-sm { @apply px-3 py-1 text-sm; }
        .btn-primary { @apply bg-blue-600 hover:bg-blue-700 focus:ring-blue-500; }
        .btn-secondary { @apply bg-slate-500 hover:bg-slate-600 focus:ring-slate-400; }
        .btn-green { @apply bg-emerald-600 hover:bg-emerald-700 focus:ring-emerald-500; }
        .btn-yellow { @apply bg-amber-500 hover:bg-amber-600 focus:ring-amber-400; }
        .btn-red { @apply bg-red-600 hover:bg-red-700 focus:ring-red-500; }
        .btn-teal { @apply bg-teal-600 hover:bg-teal-700 focus:ring-teal-500; }
        .card { @apply bg-white p-6 rounded-xl shadow-md border border-slate-200; }
        .input-field { @apply mt-1 block w-full px-3 py-2 bg-white border border-slate-300 rounded-md shadow-sm placeholder-slate-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500; }
        dialog::backdrop { background: rgba(0, 0, 0, 0.5); }
        .low-stock { background-color: #FFFBEB !important; border-color: #FBBF24 !important; }
        .expired { background-color: #FEF2F2 !important; border-color: #F87171 !important; }
    </style>
</head>
<body class="bg-slate-100 text-slate-700">

    <div id="app" class="container mx-auto p-4 md:p-8">
        
        <header class="text-center mb-8">
            <h1 class="text-4xl font-bold text-slate-800">实验室耗材管理系统</h1>
            <p class="text-slate-600 mt-2">您的所有操作记录自动保存在浏览器缓存中，务必注意定期导出库存快照备份！！！。</p>
        </header>

        <!-- 控制区域 -->
        <div class="card mb-8">
            <h2 class="text-2xl font-bold text-slate-800 mb-4 border-b pb-3">数据管理与备份</h2>
            <div class="flex flex-wrap gap-4 items-center">
                <button id="export-snapshot-btn" class="btn btn-primary">导出库存快照</button>
                <button id="export-log-btn" class="btn btn-primary">导出操作日志</button>
                <label for="load-data-input" class="btn btn-secondary cursor-pointer">从快照恢复</label>
                <input type="file" id="load-data-input" class="hidden" accept=".csv">
                <button id="shopping-list-btn" class="btn btn-teal">生成购物清单</button>
                <button id="clear-data-btn" class="btn btn-red">清除本地缓存</button>
                <p id="file-info" class="text-sm text-slate-500"></p>
            </div>
        </div>

        <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
            <!-- 库存列表 -->
            <div class="card lg:col-span-2">
                <div class="flex flex-wrap justify-between items-center mb-4 border-b border-slate-200 pb-3 gap-4">
                    <h2 class="text-2xl font-bold text-slate-800">当前库存</h2>
                    <div class="flex-grow sm:flex-grow-0 flex flex-wrap items-center gap-2">
                        <select id="location-filter" class="input-field w-full sm:w-40">
                            <option value="all">所有位置</option>
                        </select>
                        <input type="text" id="search-input" placeholder="搜索耗材名称..." class="input-field w-full sm:w-48">
                        <select id="sort-select" class="input-field w-full sm:w-auto">
                            <option value="name-asc">名称升序</option>
                            <option value="name-desc">名称降序</option>
                            <option value="stock-asc">库存升序</option>
                            <option value="stock-desc">库存降序</option>
                            <option value="expiry-asc">效期升序</option>
                            <option value="expiry-desc">效期降序</option>
                        </select>
                    </div>
                </div>
                <div id="inventory-list" class="space-y-4 max-h-[65vh] overflow-y-auto pr-2">
                    <!-- 库存项目将在这里动态生成 -->
                </div>
                <p id="inventory-placeholder" class="text-center text-slate-500 py-8">库存为空。请点击下方按钮添加新的耗材。</p>
                <button id="add-new-item-btn" class="btn btn-green w-full mt-4">＋ 添加新耗材</button>
            </div>

            <!-- 操作日志 -->
            <div class="card">
                <h2 class="text-2xl font-bold text-slate-800 mb-4 border-b border-slate-200 pb-3">操作日志</h2>
                <div class="overflow-y-auto max-h-[75vh]">
                    <table class="min-w-full divide-y divide-slate-200">
                        <thead class="bg-slate-200 sticky top-0">
                            <tr>
                                <th class="px-2 py-3 text-left text-xs font-medium text-slate-600 uppercase tracking-wider">时间</th>
                                <th class="px-2 py-3 text-left text-xs font-medium text-slate-600 uppercase tracking-wider">耗材</th>
                                <th class="px-2 py-3 text-left text-xs font-medium text-slate-600 uppercase tracking-wider">操作</th>
                                <th class="px-2 py-3 text-left text-xs font-medium text-slate-600 uppercase tracking-wider">用户</th>
                            </tr>
                        </thead>
                        <tbody id="log-table-body" class="bg-white divide-y divide-slate-200"></tbody>
                    </table>
                </div>
                <p id="log-placeholder" class="text-center text-slate-500 py-8">暂无操作记录。</p>
            </div>
        </div>
    </div>

    <!-- 操作/编辑模态框 -->
    <dialog id="action-modal" class="p-6 bg-white rounded-xl shadow-xl w-11/12 max-w-lg">
        <h3 id="modal-title" class="text-2xl font-bold text-slate-800 mb-6">执行操作</h3>
        <form id="action-form" class="space-y-4">
            <input type="hidden" id="modal-item-name">
            <input type="hidden" id="modal-action-type">

            <div id="item-details-fields">
                <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
                    <div>
                        <label for="modal-item-name-input" class="block text-sm font-medium text-slate-700">耗材名称</label>
                        <input type="text" id="modal-item-name-input" class="input-field" placeholder="例如: PBS缓冲液" required>
                    </div>
                    <div>
                        <label for="modal-unit" class="block text-sm font-medium text-slate-700">单位</label>
                        <input type="text" id="modal-unit" class="input-field" placeholder="例如: 瓶, 盒, mL" required>
                    </div>
                    <div>
                        <label for="modal-location" class="block text-sm font-medium text-slate-700">存放位置</label>
                        <input type="text" id="modal-location" class="input-field" placeholder="例如: 4°C冰箱">
                    </div>
                    <div>
                        <label for="modal-catalog-no" class="block text-sm font-medium text-slate-700">货号/目录号</label>
                        <input type="text" id="modal-catalog-no" class="input-field" placeholder="例如: P5493">
                    </div>
                    <div>
                        <label for="modal-expiry" class="block text-sm font-medium text-slate-700">过期日期</label>
                        <input type="date" id="modal-expiry" class="input-field">
                    </div>
                    <div>
                        <label for="modal-low-stock" class="block text-sm font-medium text-slate-700">低库存阈值</label>
                        <input type="number" id="modal-low-stock" class="input-field" min="0" placeholder="例如: 5">
                    </div>
                </div>
            </div>

            <div id="transaction-fields" class="pt-4 border-t border-slate-200">
                 <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
                    <div>
                        <label for="modal-quantity" class="block text-sm font-medium text-slate-700">数量</label>
                        <input type="number" id="modal-quantity" class="input-field" min="1" required>
                    </div>
                    <div>
                        <label for="modal-user" class="block text-sm font-medium text-slate-700">操作人姓名</label>
                        <input type="text" id="modal-user" class="input-field" required placeholder="例如: 张三">
                    </div>
                </div>
            </div>

            <div class="flex justify-end gap-4 pt-6">
                <button type="button" id="modal-cancel-btn" class="btn btn-secondary">取消</button>
                <button type="submit" id="modal-confirm-btn" class="btn btn-primary">确认</button>
            </div>
        </form>
    </dialog>
    
    <!-- 购物清单模态框 -->
    <dialog id="shopping-list-modal" class="p-6 bg-white rounded-xl shadow-xl w-11/12 max-w-2xl">
        <h3 class="text-2xl font-bold text-slate-800 mb-4">购物清单</h3>
        <p class="text-slate-600 mb-4">以下是所有库存量低于设定阈值的耗材。</p>
        <div id="shopping-list-content" class="bg-slate-50 p-4 rounded-lg max-h-96 overflow-y-auto"></div>
        <div class="flex justify-end gap-4 mt-6">
            <button id="copy-shopping-list-btn" class="btn btn-teal">复制清单</button>
            <button onclick="document.getElementById('shopping-list-modal').close()" class="btn btn-secondary">关闭</button>
        </div>
    </dialog>


    <script>
    document.addEventListener('DOMContentLoaded', () => {
        // --- DOM 元素获取 ---
        const inventoryList = document.getElementById('inventory-list');
        const logTableBody = document.getElementById('log-table-body');
        const exportSnapshotBtn = document.getElementById('export-snapshot-btn');
        const exportLogBtn = document.getElementById('export-log-btn');
        const loadDataInput = document.getElementById('load-data-input');
        const clearDataBtn = document.getElementById('clear-data-btn');
        const shoppingListBtn = document.getElementById('shopping-list-btn');
        const fileInfo = document.getElementById('file-info');
        const inventoryPlaceholder = document.getElementById('inventory-placeholder');
        const logPlaceholder = document.getElementById('log-placeholder');
        const searchInput = document.getElementById('search-input');
        const sortSelect = document.getElementById('sort-select');
        const locationFilter = document.getElementById('location-filter');
        const addNewItemBtn = document.getElementById('add-new-item-btn');

        const modal = document.getElementById('action-modal');
        const modalTitle = document.getElementById('modal-title');
        const actionForm = document.getElementById('action-form');
        const modalItemName = document.getElementById('modal-item-name');
        const modalActionType = document.getElementById('modal-action-type');
        
        const itemDetailsFields = document.getElementById('item-details-fields');
        const transactionFields = document.getElementById('transaction-fields');
        const modalItemNameInput = document.getElementById('modal-item-name-input');
        const modalUnitInput = document.getElementById('modal-unit');
        const modalLocationInput = document.getElementById('modal-location');
        const modalCatalogNoInput = document.getElementById('modal-catalog-no');
        const modalExpiryInput = document.getElementById('modal-expiry');
        const modalLowStockInput = document.getElementById('modal-low-stock');
        const modalQuantityInput = document.getElementById('modal-quantity');
        const modalUserInput = document.getElementById('modal-user');
        const modalCancelBtn = document.getElementById('modal-cancel-btn');
        
        const shoppingListModal = document.getElementById('shopping-list-modal');
        const shoppingListContent = document.getElementById('shopping-list-content');
        const copyShoppingListBtn = document.getElementById('copy-shopping-list-btn');

        let inventory = {};
        let log = [];
        const LOCAL_STORAGE_KEY = 'labInventoryData-v3';

        const saveStateToLocalStorage = () => {
            try {
                localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify({ inventory, log }));
            } catch (e) { console.error("无法保存到LocalStorage:", e); }
        };

        const loadStateFromLocalStorage = () => {
            try {
                const savedState = localStorage.getItem(LOCAL_STORAGE_KEY);
                if (savedState) {
                    const parsed = JSON.parse(savedState);
                    inventory = parsed.inventory || {};
                    log = parsed.log || [];
                    fileInfo.textContent = '已自动从浏览器缓存加载上次的数据。';
                }
            } catch (e) {
                console.error("无法从LocalStorage加载:", e);
                fileInfo.textContent = "加载缓存数据失败。";
            }
        };

        const render = () => {
            renderInventory();
            renderLog();
            updatePlaceholders();
        };

        const getExpiryStatus = (expiryDate) => {
            if (!expiryDate) return { status: 'ok', text: '无' };
            const now = new Date();
            const expiry = new Date(expiryDate);
            now.setHours(0, 0, 0, 0);
            expiry.setHours(0, 0, 0, 0);
            const diffDays = (expiry - now) / (1000 * 60 * 60 * 24);

            if (diffDays < 0) return { status: 'expired', text: `已过期 ${-diffDays} 天` };
            if (diffDays <= 30) return { status: 'expiring', text: `${diffDays} 天后过期` };
            return { status: 'ok', text: expiryDate };
        };

        const renderInventory = () => {
            const currentLocation = locationFilter.value;
            const locations = ['all', ...new Set(Object.values(inventory).map(item => item.location).filter(Boolean).sort())];
            locationFilter.innerHTML = '';
            locations.forEach(loc => {
                const option = document.createElement('option');
                option.value = loc;
                option.textContent = loc === 'all' ? '所有位置' : loc;
                locationFilter.appendChild(option);
            });
            if (locations.includes(currentLocation)) {
                locationFilter.value = currentLocation;
            }

            inventoryList.innerHTML = '';
            const searchTerm = searchInput.value.toLowerCase();
            const selectedLocation = locationFilter.value;
            const [sortKey, sortDir] = sortSelect.value.split('-');

            let items = Object.entries(inventory)
                .filter(([name, item]) => {
                    const nameMatch = name.toLowerCase().includes(searchTerm);
                    const locationMatch = selectedLocation === 'all' || item.location === selectedLocation;
                    return nameMatch && locationMatch;
                });

            items.sort(([, a], [, b]) => {
                let valA, valB;
                switch (sortKey) {
                    case 'stock': valA = a.stock; valB = b.stock; break;
                    case 'expiry':
                        valA = a.expiryDate ? new Date(a.expiryDate) : new Date('9999-12-31');
                        valB = b.expiryDate ? new Date(b.expiryDate) : new Date('9999-12-31');
                        break;
                    default: valA = a.name.toLowerCase(); valB = b.name.toLowerCase(); break;
                }
                if (valA < valB) return sortDir === 'asc' ? -1 : 1;
                if (valA > valB) return sortDir === 'asc' ? 1 : -1;
                return 0;
            });

            if (items.length === 0 && Object.keys(inventory).length > 0) {
                 inventoryList.innerHTML = `<p class="text-center text-slate-500 py-8">在当前筛选条件下没有找到结果。</p>`;
                 return;
            }
            if (items.length === 0) return;

            items.forEach(([name, item]) => {
                const expiry = getExpiryStatus(item.expiryDate);
                let classes = 'bg-slate-50 p-4 rounded-lg border border-slate-200';
                if (item.stock <= (item.lowStockThreshold || 0) && item.stock > 0) classes += ' low-stock';
                if (expiry.status === 'expired' || expiry.status === 'expiring') classes += ' expired';

                const itemElement = document.createElement('div');
                itemElement.className = classes;
                itemElement.innerHTML = `
                    <div class="flex justify-between items-start">
                        <div>
                            <h3 class="font-bold text-xl text-slate-800">${item.name}</h3>
                            <p class="text-sm text-slate-500">货号: ${item.catalogNo || 'N/A'} | 位置: ${item.location || 'N/A'}</p>
                        </div>
                        <div class="flex gap-2 flex-shrink-0">
                            <button class="btn btn-sm btn-yellow" onclick="showModal('use', '${CSS.escape(name)}')">领用</button>
                            <button class="btn btn-sm btn-green" onclick="showModal('restock', '${CSS.escape(name)}')">补充</button>
                            <button class="btn btn-sm btn-secondary" onclick="showModal('edit', '${CSS.escape(name)}')">编辑</button>
                            <button class="btn btn-sm btn-red" onclick="deleteItem('${CSS.escape(name)}')">删除</button>
                        </div>
                    </div>
                    <div class="mt-3 flex justify-between items-center text-center">
                        <div>
                            <p class="text-xs text-slate-500">当前库存</p>
                            <p class="font-bold text-2xl text-slate-800">${item.stock} <span class="text-base font-normal text-slate-600">${item.unit}</span></p>
                        </div>
                        <div>
                            <p class="text-xs text-slate-500">过期状态</p>
                            <p class="font-semibold text-sm ${expiry.status !== 'ok' ? 'text-red-600' : 'text-slate-600'}">
                                ${expiry.status !== 'ok' ? `<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 inline-block mr-1" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.22 3.001-1.742 3.001H4.42c-1.522 0-2.492-1.667-1.742-3.001l5.58-9.92zM10 13a1 1 0 110-2 1 1 0 010 2zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" /></svg>` : ''}
                                ${expiry.text}
                            </p>
                        </div>
                    </div>
                `;
                inventoryList.appendChild(itemElement);
            });
        };

        const renderLog = () => {
            logTableBody.innerHTML = '';
            [...log].reverse().forEach(entry => {
                const actionClass = entry.action === '领用' ? 'text-red-600' : 'text-emerald-600';
                const row = logTableBody.insertRow();
                row.innerHTML = `
                    <td class="px-2 py-3 whitespace-nowrap text-xs text-slate-500">${new Date(entry.timestamp).toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })}</td>
                    <td class="px-2 py-3 whitespace-nowrap text-sm font-medium text-slate-800">${entry.itemName}</td>
                    <td class="px-2 py-3 whitespace-nowrap text-sm font-semibold ${actionClass}">${entry.action} (${entry.quantity}${entry.unit})</td>
                    <td class="px-2 py-3 whitespace-nowrap text-sm text-slate-600">${entry.user}</td>
                `;
            });
        };

        const updatePlaceholders = () => {
            inventoryPlaceholder.style.display = Object.keys(inventory).length === 0 ? 'block' : 'none';
            logPlaceholder.style.display = log.length === 0 ? 'block' : 'none';
        };

        window.showModal = (actionType, itemName = '') => {
            actionForm.reset();
            modalActionType.value = actionType;
            modalItemName.value = itemName;
            
            const isNew = actionType === 'add';
            const isEdit = actionType === 'edit';
            const isTransaction = actionType === 'use' || actionType === 'restock';

            itemDetailsFields.style.display = isNew || isEdit ? 'block' : 'none';
            transactionFields.style.display = isTransaction ? 'block' : 'none';
            modalItemNameInput.readOnly = !isNew;

            if (isNew) {
                modalTitle.textContent = '添加新耗材';
                transactionFields.style.display = 'block';
                modalQuantityInput.required = true;
                modalUserInput.required = true;
            } else if (isEdit) {
                modalTitle.textContent = `编辑 - ${itemName}`;
                const item = inventory[itemName];
                modalItemNameInput.value = item.name;
                modalUnitInput.value = item.unit;
                modalLocationInput.value = item.location || '';
                modalCatalogNoInput.value = item.catalogNo || '';
                modalExpiryInput.value = item.expiryDate || '';
                modalLowStockInput.value = item.lowStockThreshold || '';
            } else if (isTransaction) {
                modalTitle.textContent = `${actionType === 'use' ? '领用' : '补充'} - ${itemName}`;
                const item = inventory[itemName];
                modalQuantityInput.max = actionType === 'use' ? item.stock : '';
                modalQuantityInput.placeholder = actionType === 'use' ? `最多可领用 ${item.stock}` : '输入补充数量';
            }
            modal.showModal();
        };
        
        window.deleteItem = (itemName) => {
            if (confirm(`确定要删除耗材 "${itemName}" 吗？\n此操作将移除该物品及其所有相关的操作日志，且无法恢复。`)) {
                delete inventory[itemName];
                log = log.filter(entry => entry.itemName !== itemName);
                saveStateToLocalStorage();
                render();
            }
        };

        actionForm.addEventListener('submit', (e) => {
            e.preventDefault();
            const actionType = modalActionType.value;
            const originalItemName = modalItemName.value;
            
            if (actionType === 'add' || actionType === 'edit') {
                const newName = modalItemNameInput.value.trim();
                if (!newName) { alert('耗材名称不能为空！'); return; }

                if (actionType === 'add' && inventory[newName]) {
                    alert('该耗材名称已存在！'); return;
                }
                
                const updatedDetails = {
                    name: newName,
                    unit: modalUnitInput.value.trim(),
                    location: modalLocationInput.value.trim(),
                    catalogNo: modalCatalogNoInput.value.trim(),
                    expiryDate: modalExpiryInput.value,
                    lowStockThreshold: parseInt(modalLowStockInput.value, 10) || 0,
                    stock: inventory[originalItemName]?.stock || 0
                };

                if (actionType === 'edit' && newName !== originalItemName) {
                    if (inventory[newName]) {
                        alert('新的耗材名称已存在！'); return;
                    }
                    inventory[newName] = { ...updatedDetails, stock: inventory[originalItemName].stock };
                    delete inventory[originalItemName];
                    log.forEach(entry => {
                        if (entry.itemName === originalItemName) entry.itemName = newName;
                    });
                } else {
                    inventory[newName] = { ...inventory[newName], ...updatedDetails };
                }

                if (actionType === 'add') {
                    const quantity = parseInt(modalQuantityInput.value, 10);
                    const user = modalUserInput.value.trim();
                    if (!quantity || !user) { alert('初始数量和操作人不能为空！'); return; }
                    inventory[newName].stock = quantity;
                    log.push({ timestamp: new Date().toISOString(), itemName: newName, action: '补充', quantity, user, unit: inventory[newName].unit });
                }

            } else if (actionType === 'use' || actionType === 'restock') {
                const quantity = parseInt(modalQuantityInput.value, 10);
                const user = modalUserInput.value.trim();
                const item = inventory[originalItemName];
                
                if (actionType === 'use' && quantity > item.stock) {
                    alert('领用数量不能超过库存！'); return;
                }

                item.stock += (actionType === 'use' ? -quantity : quantity);
                log.push({ timestamp: new Date().toISOString(), itemName: originalItemName, action: actionType === 'use' ? '领用' : '补充', quantity, user, unit: item.unit });
            }

            saveStateToLocalStorage();
            render();
            modal.close();
        });

        addNewItemBtn.addEventListener('click', () => showModal('add'));
        modalCancelBtn.addEventListener('click', () => modal.close());
        searchInput.addEventListener('input', renderInventory);
        sortSelect.addEventListener('change', renderInventory);
        locationFilter.addEventListener('change', renderInventory);

        const downloadCSV = (filename, csvString) => {
            const blob = new Blob([`\uFEFF${csvString}`], { type: 'text/csv;charset=utf-8;' });
            const link = document.createElement('a');
            link.href = URL.createObjectURL(blob);
            link.download = filename;
            link.click();
            URL.revokeObjectURL(link.href);
        };

        exportSnapshotBtn.addEventListener('click', () => {
            if (Object.keys(inventory).length === 0) { alert('没有库存数据可以导出。'); return; }
            const headers = ['品名', '货号', '位置', '单位', '当前库存', '库存阈值', '过期日期'];
            const csvRows = Object.values(inventory).map(item =>
                [item.name, item.catalogNo, item.location, item.unit, item.stock, item.lowStockThreshold, item.expiryDate]
                .map(val => `"${(val || '').toString().replace(/"/g, '""')}"`).join(',')
            );
            const csvString = [headers.join(','), ...csvRows].join('\n');
            downloadCSV(`库存快照-${new Date().toISOString().slice(0, 10)}.csv`, csvString);
        });

        exportLogBtn.addEventListener('click', () => {
            if (log.length === 0) { alert('没有操作日志可以导出。'); return; }
            const headers = ['时间戳', '品名', '操作类型', '数量变化', '操作后库存', '操作人', '单位'];
            
            const tempInventory = {};
            const logWithStock = log.map(entry => {
                if (tempInventory[entry.itemName] === undefined) {
                    tempInventory[entry.itemName] = 0;
                }
                const quantityChange = entry.action === '补充' ? entry.quantity : -entry.quantity;
                tempInventory[entry.itemName] += quantityChange;
                const stockAfter = tempInventory[entry.itemName];
                
                return {
                    ...entry,
                    transactionType: entry.action === '补充' ? '入库' : '出库',
                    quantityChange: quantityChange,
                    stockAfter: stockAfter
                };
            });

            const csvRows = logWithStock.map(entry =>
                [entry.timestamp, entry.itemName, entry.transactionType, entry.quantityChange, entry.stockAfter, entry.user, entry.unit]
                .map(val => `"${(val || '').toString().replace(/"/g, '""')}"`).join(',')
            );
            const csvString = [headers.join(','), ...csvRows].join('\n');
            downloadCSV(`操作日志-${new Date().toISOString().slice(0, 10)}.csv`, csvString);
        });
        
        loadDataInput.addEventListener('change', (event) => {
            const file = event.target.files[0];
            if (!file) return;
            if (!confirm("从CSV库存快照恢复将覆盖当前所有数据（操作日志将被清空），确定吗？")) {
                loadDataInput.value = ''; return;
            }
            
            const reader = new FileReader();
            reader.onload = (e) => {
                try {
                    const text = e.target.result;
                    const rows = text.split(/\r?\n/).filter(row => row.trim() !== '');
                    if (rows.length < 2) throw new Error('CSV文件为空或格式不正确。');

                    const newInventory = {};
                    const headerRow = rows.shift();
                    // Regex to handle quoted fields
                    const csvRegex = /(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)/g;
                    const headers = [...headerRow.matchAll(csvRegex)].map(match => match[1].replace(/^"|"$/g, '').replace(/""/g, '"'));

                    const colMap = {
                        name: headers.indexOf('品名'),
                        catalogNo: headers.indexOf('货号'),
                        location: headers.indexOf('位置'),
                        unit: headers.indexOf('单位'),
                        stock: headers.indexOf('当前库存'),
                        lowStockThreshold: headers.indexOf('库存阈值'),
                        expiryDate: headers.indexOf('过期日期')
                    };

                    if (colMap.name === -1 || colMap.stock === -1) {
                        throw new Error('CSV文件缺少必要的列 (至少需要 "品名" 和 "当前库存")');
                    }

                    rows.forEach(rowStr => {
                        const values = [...rowStr.matchAll(csvRegex)].map(match => match[1].replace(/^"|"$/g, '').replace(/""/g, '"'));
                        const name = values[colMap.name];
                        if (!name) return; // Skip empty rows

                        newInventory[name] = {
                            name: name,
                            catalogNo: values[colMap.catalogNo] || '',
                            location: values[colMap.location] || '',
                            unit: values[colMap.unit] || '个',
                            stock: parseInt(values[colMap.stock], 10) || 0,
                            lowStockThreshold: parseInt(values[colMap.lowStockThreshold], 10) || 0,
                            expiryDate: values[colMap.expiryDate] || ''
                        };
                    });
                    
                    inventory = newInventory;
                    log = []; // Reset log when restoring from a snapshot
                    saveStateToLocalStorage();
                    render();
                    fileInfo.textContent = `已成功从 ${file.name} 恢复库存快照。`;

                } catch (error) {
                    alert(`加载文件失败: ${error.message}`);
                } finally {
                    loadDataInput.value = '';
                }
            };
            reader.readAsText(file);
        });

        clearDataBtn.addEventListener('click', () => {
            if (confirm("确定要清除所有本地缓存数据吗？此操作不可恢复。")) {
                localStorage.removeItem(LOCAL_STORAGE_KEY);
                inventory = {}; log = [];
                fileInfo.textContent = '本地缓存已清除。';
                render();
            }
        });

        shoppingListBtn.addEventListener('click', () => {
            const itemsToOrder = Object.values(inventory).filter(item => item.stock <= (item.lowStockThreshold || 0));
            if (itemsToOrder.length === 0) {
                shoppingListContent.innerHTML = '<p>太棒了！目前没有需要采购的耗材。</p>';
            } else {
                shoppingListContent.innerHTML = `
                    <table class="min-w-full">
                        <thead><tr>
                            <th class="text-left font-semibold p-2 text-slate-700">耗材名称</th>
                            <th class="text-left font-semibold p-2 text-slate-700">货号</th>
                            <th class="text-left font-semibold p-2 text-slate-700">当前库存</th>
                        </tr></thead>
                        <tbody>
                        ${itemsToOrder.map(item => `
                            <tr class="border-t border-slate-200">
                                <td class="p-2 text-slate-800">${item.name}</td>
                                <td class="p-2 text-slate-600">${item.catalogNo || 'N/A'}</td>
                                <td class="p-2 text-slate-800">${item.stock} ${item.unit}</td>
                            </tr>
                        `).join('')}
                        </tbody>
                    </table>`;
            }
            shoppingListModal.showModal();
        });

        copyShoppingListBtn.addEventListener('click', () => {
            const textToCopy = shoppingListContent.innerText;
            navigator.clipboard.writeText(textToCopy).then(() => {
                alert('购物清单已复制到剪贴板！');
            }, () => {
                alert('复制失败，您的浏览器可能不支持此功能。');
            });
        });

        loadStateFromLocalStorage();
        render();
    });
    </script>
</body>
</html>
